package com.fish.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fish.common.exception.BusinessException;
import com.fish.common.result.ResultCode;
import com.fish.dao.mapper.RoleMapper;
import com.fish.dao.mapper.RoleMenuMapper;
import com.fish.dao.mapper.UserRoleMapper;
import com.fish.model.dto.RoleDTO;
import com.fish.model.entity.Role;
import com.fish.model.entity.RoleMenu;
import com.fish.model.entity.UserRole;
import com.fish.model.vo.RoleVO;
import com.fish.service.MenuService;
import com.fish.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色服务实现类
 */
@Slf4j
@Service
public class RoleServiceImpl implements RoleService {
    
    @Autowired
    private RoleMapper roleMapper;
    
    @Autowired
    private UserRoleMapper userRoleMapper;
    
    @Autowired
    private RoleMenuMapper roleMenuMapper;
    
    @Autowired
    private MenuService menuService;
    
    @Override
    public List<Role> getRolesByUserId(Long userId) {
        return roleMapper.selectRolesByUserId(userId);
    }
    
    @Override
    public List<RoleVO> getAllRoles() {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Role::getStatus, 1);
        wrapper.orderByAsc(Role::getId);
        
        List<Role> roles = roleMapper.selectList(wrapper);
        
        return roles.stream().map(role -> {
            RoleVO roleVO = new RoleVO();
            BeanUtil.copyProperties(role, roleVO);
            // 查询角色关联的菜单ID列表
            List<Long> menuIds = menuService.getMenuIdsByRoleId(role.getId());
            roleVO.setMenuIds(menuIds);
            return roleVO;
        }).collect(Collectors.toList());
    }
    
    @Override
    public RoleVO getRoleById(Long roleId) {
        Role role = roleMapper.selectById(roleId);
        if (role == null) {
            return null;
        }
        
        RoleVO roleVO = new RoleVO();
        BeanUtil.copyProperties(role, roleVO);
        
        // 查询角色关联的菜单ID列表
        List<Long> menuIds = menuService.getMenuIdsByRoleId(roleId);
        roleVO.setMenuIds(menuIds);
        
        return roleVO;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignRolesToUser(Long userId, List<Long> roleIds) {
        // 先删除用户已有的角色关联
        LambdaQueryWrapper<UserRole> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(UserRole::getUserId, userId);
        userRoleMapper.delete(deleteWrapper);
        
        // 添加新的角色关联
        if (roleIds != null && !roleIds.isEmpty()) {
            for (Long roleId : roleIds) {
                UserRole userRole = new UserRole();
                userRole.setUserId(userId);
                userRole.setRoleId(roleId);
                userRoleMapper.insert(userRole);
            }
        }
        
        // 清除该用户的菜单和权限缓存
        if (menuService instanceof MenuServiceImpl) {
            ((MenuServiceImpl) menuService).clearUserCache(userId);
        }
        
        log.info("为用户[{}]分配角色成功，角色ID列表：{}", userId, roleIds);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RoleVO addRole(RoleDTO roleDTO) {
        // 1. 检查角色标识是否已存在
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Role::getRoleKey, roleDTO.getRoleKey());
        Role existRole = roleMapper.selectOne(wrapper);
        if (existRole != null) {
            throw new BusinessException("角色标识已存在");
        }
        
        // 2. 创建角色
        Role role = new Role();
        BeanUtil.copyProperties(roleDTO, role);
        role.setStatus(roleDTO.getStatus() != null ? roleDTO.getStatus() : 1);
        
        int result = roleMapper.insert(role);
        if (result <= 0) {
            throw new BusinessException("添加角色失败");
        }
        
        // 3. 分配菜单权限
        if (roleDTO.getMenuIds() != null && !roleDTO.getMenuIds().isEmpty()) {
            assignMenusToRole(role.getId(), roleDTO.getMenuIds());
        }
        
        log.info("添加角色成功，角色名称：{}", role.getRoleName());
        return getRoleById(role.getId());
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RoleVO updateRole(RoleDTO roleDTO) {
        // 1. 检查角色是否存在
        Role role = roleMapper.selectById(roleDTO.getId());
        if (role == null) {
            throw new BusinessException("角色不存在");
        }
        
        // 2. 检查角色标识是否被其他角色使用
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Role::getRoleKey, roleDTO.getRoleKey());
        wrapper.ne(Role::getId, roleDTO.getId());
        Role existRole = roleMapper.selectOne(wrapper);
        if (existRole != null) {
            throw new BusinessException("角色标识已被使用");
        }
        
        // 3. 更新角色信息
        role.setRoleName(roleDTO.getRoleName());
        role.setRoleKey(roleDTO.getRoleKey());
        role.setDescription(roleDTO.getDescription());
        if (roleDTO.getStatus() != null) {
            role.setStatus(roleDTO.getStatus());
        }
        
        int result = roleMapper.updateById(role);
        if (result <= 0) {
            throw new BusinessException("更新角色失败");
        }
        
        // 4. 更新菜单权限
        if (roleDTO.getMenuIds() != null) {
            assignMenusToRole(role.getId(), roleDTO.getMenuIds());
        }
        
        log.info("更新角色成功，角色ID：{}", role.getId());
        return getRoleById(role.getId());
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRole(Long roleId) {
        // 1. 检查角色是否存在
        Role role = roleMapper.selectById(roleId);
        if (role == null) {
            throw new BusinessException("角色不存在");
        }
        
        // 2. 检查是否有用户使用该角色
        LambdaQueryWrapper<UserRole> userRoleWrapper = new LambdaQueryWrapper<>();
        userRoleWrapper.eq(UserRole::getRoleId, roleId);
        Long count = userRoleMapper.selectCount(userRoleWrapper);
        if (count > 0) {
            throw new BusinessException("该角色已分配给用户，无法删除");
        }
        
        // 3. 删除角色
        int result = roleMapper.deleteById(roleId);
        if (result <= 0) {
            throw new BusinessException("删除角色失败");
        }
        
        // 4. 删除角色菜单关联
        LambdaQueryWrapper<RoleMenu> roleMenuWrapper = new LambdaQueryWrapper<>();
        roleMenuWrapper.eq(RoleMenu::getRoleId, roleId);
        roleMenuMapper.delete(roleMenuWrapper);
        
        log.info("删除角色成功，角色ID：{}", roleId);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignMenusToRole(Long roleId, List<Long> menuIds) {
        // 1. 删除原有的角色菜单关联
        LambdaQueryWrapper<RoleMenu> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(RoleMenu::getRoleId, roleId);
        roleMenuMapper.delete(deleteWrapper);
        
        // 2. 添加新的角色菜单关联
        if (menuIds != null && !menuIds.isEmpty()) {
            for (Long menuId : menuIds) {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setRoleId(roleId);
                roleMenu.setMenuId(menuId);
                roleMenuMapper.insert(roleMenu);
            }
        }
        
        // 3. 清除拥有该角色的所有用户的缓存
        clearUsersCacheByRole(roleId);
        
        log.info("为角色[{}]分配菜单权限成功，菜单ID列表：{}", roleId, menuIds);
    }
    
    /**
     * 清除拥有指定角色的所有用户的缓存
     */
    private void clearUsersCacheByRole(Long roleId) {
        // 查询拥有该角色的所有用户
        LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserRole::getRoleId, roleId);
        List<UserRole> userRoles = userRoleMapper.selectList(wrapper);
        
        // 清除每个用户的缓存
        for (UserRole userRole : userRoles) {
            if (menuService instanceof MenuServiceImpl) {
                ((MenuServiceImpl) menuService).clearUserCache(userRole.getUserId());
            }
        }
        
        log.info("清除角色[{}]相关用户缓存，影响用户数：{}", roleId, userRoles.size());
    }
}